package com.moose.aop.aspect;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.moose.aop.annotation.Log;
import com.moose.entity.log.OperateLog;
import com.moose.entity.sys.SysRole;
import com.moose.entity.sys.SysUser;
import com.moose.security.util.SecurityUtil;
import com.moose.service.log.OperateLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Instant;
import java.util.stream.Collectors;

/**
 * 日志切面
 *
 * @author 唐国翔
 * @since 2018-12-17 16:07
 * <p>
 * 　　　　　　　　┏┓　　　┏┓+ +
 * 　　　　　　　┏┛┻━━━┛┻┓ + +
 * 　　　　　　　┃　　　　　　　┃
 * 　　　　　　　┃　　　━　　　┃ ++ + + +
 * 　　　　　　 ████━████ ┃+
 * 　　　　　　　┃　　　　　　　┃ +
 * 　　　　　　　┃　　　┻　　　┃
 * 　　　　　　　┃　　　　　　　┃ + +
 * 　　　　　　　┗━┓　　　  ┏━┛
 * 　　　　　　　　　┃　　　┃
 * 　　　　　　　　　┃　　　┃ + + + +
 * 　　　　　　　　　┃　　　┃　　　　Code is far away from bug with the animal protecting
 * 　　　　　　　　　┃　　　┃ + 　　　　神兽保佑,代码无bug
 * 　　　　　　　　　┃　　　┃
 * 　　　　　　　　　┃　　　┃　　+
 * 　　　　　　　　　┃　 　　┗━━━┓ + +
 * 　　　　　　　　　┃ 　　　　　　　┣┓
 * 　　　　　　　　　┃ 　　　　　　　┏┛
 * 　　　　　　　　　┗┓┓┏━┳┓┏┛ + + + +
 * 　　　　　　　　　　┃┫┫　┃┫┫
 * 　　　　　　　　　　┗┻┛　┗┻┛+ + + +
 **/
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Resource
    private OperateLogService operateLogService;

    private LogAspect() {
    }

    /**
     * 切点Log注解方法
     */
    @Pointcut("@annotation(com.moose.aop.annotation.Log)")
    public void pointCut() {
    }

    /**
     * @author 唐国翔
     * @Description 记录操作日志、方法执行时间
     * @since 2018/12/17 16:20
     **/
    @Around("pointCut()")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {

        long start = System.currentTimeMillis();

        //方法返回值
        Object result;
        //获取方法描述
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        StringBuffer desc = new StringBuffer(signature.getMethod().getAnnotation(Log.class).desc());
        //获取当前登陆信息
        SysUser sysUser = (SysUser) SecurityUtil.getCurrentUserInfo();
        //获取当前登陆用户ip
        String ip = SecurityUtil.getCurrentUserUrl();

        try {
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            //异常信息存储
            desc.append("出现异常，").append(throwable.getMessage());
            log.error(desc.toString());
            throw throwable;
        } finally {
            long end = System.currentTimeMillis();
            ThreadUtil.execute(() -> {
                //保存
                operateLogService.save(OperateLog.builder()
                        .operator(sysUser.getName())
                        //多角色用","隔开
                        .operateRole(sysUser.getRoles().stream().map(SysRole::getRoleName).collect(Collectors.joining(StrUtil.COMMA)))
                        .operateTime(Instant.now().toEpochMilli())
                        .operatorIp(ip)
                        .operateActive(desc.toString())
                        .executeTime(end - start)
                        .build());
            });
        }

        return result;
    }

}
